package com.coderxq.blog.aspect;

import com.coderxq.blog.annotation.LogAnnotation;
import com.coderxq.blog.exception.WsException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * @Author: lijingming
 * @Date: 2025/1/16
 * @Description:
 **/
//利用面向切面编程 捕获所有被LogAnnotation注解的方法 并做一些处理 例如收集该切点的操作日志
//若需要在springboot中配置切面类时 需要将该类加入到spring容器中也就是需要使用@Component注解 同时也需要@Aspect注解使该类成为一个切面类
@Aspect  //让该类成为springboot 切面对象
@Component  // 将该切面类加入到spring容器中 在项目执行时 spring内部会将该切面类加入到容器中
public class LogAspect {
    private final Logger logger = LoggerFactory.getLogger(LogAspect.class);

    @Pointcut("@annotation(com.coderxq.blog.annotation.LogAnnotation)") //找到代码种被该注解标注的方法或者也可以成为切点
    public void logPointCut() {
    }


    //找到切点之后 实际执行的是该方法
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        logger.info("开始执行around切面方法了");
        Object result = point.proceed();
        //如果方法切点执行的内部没有报错并且成功返回 但是Around切面方法这里出现了内部报错 仍然会被全局异常捕获并且抛出
        //throw new WsException("around方法抛出异常");
        String methodName = point.getSignature().getName(); //获取切点的方法名
        MethodSignature signature =(MethodSignature) point.getSignature();
        Method method=signature.getMethod();
        LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);
        if(annotation!=null){
            logger.info("Around---切点方法注解值:"+annotation.value());
        }
        logger.info("Around----切点方法名:"+methodName);
        logger.info("Around----切点方法返回结果:"+result);




        return result;
    }

    /**
     * 记录操作日志
     *
     * @param joinPoint 方法的执行点
     * @param result    方法返回值
     * @throws Throwable
     */
    @AfterReturning(returning = "result", value = "logPointCut()")
    public void saveOperLog(JoinPoint joinPoint, Object result) throws Throwable {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = (HttpServletRequest) requestAttributes
                .resolveReference(RequestAttributes.REFERENCE_REQUEST);
        String operator = (String) request.getAttribute("username");
        String operatorId = (String) request.getAttribute("userId");
        // Map<String,String> map = (Map<String, String>) result;

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        logger.info("AfterReturning----切点方法返回结果:"+result);

    }

}
